package com.fjbdxk.beidou.bd;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * 构建和解析数据包头部信息的工具，确保网络通信中数据包的结构和内容符合预定义的格式
 */
class PacketHeader {
    final static int PACK_HEADER_SIZE = 8;  // 报头长度
    final static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//用于格式化日期和时间的 SimpleDateFormat 对象，格式为 yyyy-MM-dd HH:mm:ss
    final static TimeZone tz = TimeZone.getDefault();//默认时区，使用系统的默认时区
    final static byte HEADER = (byte)0xBD;//报文起始字节
    final static byte END = (byte)0xCC;//报文结束字节
    final int len;//报文长度
    final byte vsq;//可变结构标识
    final TP type;//报文类型
    final long ldt;//时间戳
    final int optNum;//可变结构数量
    final int dataNum;//数据结构数量
    final int total;//总结构数量

    enum TP {
        TP_0(0, "风场多机组数据报文"),
        TP_1(1, "单机组多周期数据报文"),
        TP_2(2, "纯报警信息报文"),
        TP_3(3, "保留");

        // 定义一个私有字段来存储与枚举常量相关联的字符串
        private final String description;//与每个报文相关联的描述字符串
        private final int code;//报文类型的代码

        TP(int code, String description) {
            this.description = description;
            this.code = code;
        }

        public String getDescription() {
            return description;
        }//返回报文类型的描述

        public int getValue() {
           return this.code;
        }//返回报文类型的代码值

        public static TP getByCode(int code) {//根据代码返回相应的 TP 枚举值
            switch (code) {
                case 0:
                    return TP_0;

                case 1:
                    return TP_1;

                case 2:
                    return TP_2;

                case 3:
                    return TP_3;

                default:
                    return null;
            }
        }
    }

//    public PacketHeader(TP type, int len, int optNum, int dataNum, long ldt) {
//        this.type = type;
//        this.len = len;
//        this.optNum = optNum;
//        this.dataNum = dataNum;
//        this.ldt = ldt;
//        this.vsq = (byte)((type.getValue() << 6) | (optNum << 4) | dataNum);
//        this.total = optNum * 16 + dataNum;
//    }

    /**
     * 解析报文用的构造函数
     * 这个构造函数用于解析输入的字节数组（pack），并将其数据存储到相应的成员变量中
     */
    public PacketHeader(byte[] pack) throws Exception {
        if (pack.length <= 8) {
            throw new Exception("报文长度小于8个字节，不符合报文定义");
        }
        if (pack[0] != HEADER) {
            throw new Exception("报文不以 0xBD 开头，不符合报文定义");
        }

        len = 0xFF & pack[1];
        if (pack.length < len + 2) {
            throw new Exception("报文长度与报文中数据长度不匹配，不符合报文定义");
        }
        byte end = pack[len + 1];
        if (end != END) {
            throw new Exception("报文结尾字节不是 0xCC，不符合报文定义");
        }

        // 解析 TP、ON、DN
        vsq = pack[2];//计算并解析 vsq 字节以获取报文类型、可变结构数量和数据结构数量
        type = TP.getByCode((vsq & 0xC0) >> 6);
        optNum = (vsq & 0x30) >> 4;
        dataNum = vsq & 0x0F;
        total = optNum * 16 + dataNum;

        // 解析基准时间ldt，将其存储为长整型
        ldt = (Byte.toUnsignedInt(pack[3]) << 32) + (Byte.toUnsignedInt(pack[4]) << 24)
                + (Byte.toUnsignedInt(pack[5]) << 16) + (Byte.toUnsignedInt(pack[6]) << 8)
                + Byte.toUnsignedInt(pack[7]);
    }
    //格式化时间戳，将Data对象转换为5字节的字节数组，表示时间戳（单位秒），通过位运算将时间戳的各个部分填充到字节数组中
    public static byte[] formatDatetimeBytes(Date dt) {
        long ldt = dt.getTime() / 1000;
        byte[] buf = new byte[5];
        buf[0] = (byte)((ldt & 0x000000FF00000000L) >> 32);
        buf[1] = (byte)((ldt & 0xFF000000) >> 24);
        buf[2] = (byte)((ldt & 0x00FF0000) >> 16);
        buf[3] = (byte)((ldt & 0x0000FF00) >> 8);
        buf[4] = (byte)(ldt & 0x000000FF);
        return buf;
    }
    //根据报文类型、可变结构数量和数据结构数量生成 vsq 字节，使用位运算组合类型、数量并返回相应的字节
    public static byte formatVSQ(TP type, int optNum, int dataNum) {
        return (byte)((type.getValue() << 6) + (optNum << 4) + dataNum);
    }
    //用于返回该类的字符串表示，包括报文类型、时间戳、时区以及可变和数据结构的数量，使用 StringBuilder 构建字符串，便于调试和日志记录
    @Override
    public String toString() {
        Date dt = new Date(ldt*1000);
        StringBuilder builder = new StringBuilder();
        builder.append("报文类型: ").append(type.getValue()).append("(").append(type.getDescription()).append(")")
                .append(", 时间戳: ").append(SDF.format(dt)).append("[时区: ")
                .append(tz.getDisplayName()).append("(").append(tz.toZoneId()).append(")]")
                .append(", 可变结构数量ON: ").append(optNum)
                .append(", 数据结构数量DN: ").append(dataNum);
        return builder.toString();
    }
}
